package org.crystalrange.documents.web;

import java.util.Date;
import java.util.Set;

import org.crystalrange.BaseController;
import org.crystalrange.Message;
import org.crystalrange.documents.model.Document;
import org.crystalrange.documents.model.DocumentCategory;
import org.crystalrange.documents.model.DocumentGroup;
import org.crystalrange.documents.model.DocumentReference;
import org.crystalrange.documents.model.DocumentTag;
import org.crystalrange.documents.model.DocumentType;
import org.crystalrange.documents.model.DocumentVersion;
import org.crystalrange.documents.service.DocumentService;
import org.crystalrange.model.User;
import org.crystalrange.service.UserService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class DocumentController extends BaseController {

	private Document document;
	private DocumentService documentService;
	protected Listbox listboxDocumentTag;
	protected Listbox listboxDocumentGroup;
	protected Listbox listboxParentDocumentReference;
	protected Listbox listboxChildDocumentReference;
	protected Listbox listboxDocumentVersion;
	private DocumentReference selectedParentDocumentReference;
	private DocumentReference selectedChildDocumentReference;
	private DocumentVersion selectedDocumentVersion;
	private UserService userService;

	public boolean getIsDisabled() {
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		User currentUser = this.userService.findByUsername(username);
		
		if (this.document.getLockedBy() != null) {
			if (this.document.getLockedBy().getUsername().equals(currentUser.getUsername())) {
				return false;
			}
		} else if (this.document.getId() == null) {
			return false;
		}
		return true;
	}
	
	public Document getDocument() {
		return document;
	}

	public void setDocument(Document document) {
		this.document = document;
	}

	public DocumentService getDocumentService() {
		return documentService;
	}

	public void setDocumentService(DocumentService documentService) {
		this.documentService = documentService;
	}
	
	public DocumentReference getSelectedParentDocumentReference() {
		return selectedParentDocumentReference;
	}

	public void setSelectedParentDocumentReference(
			DocumentReference selectedParentDocumentReference) {
		this.selectedParentDocumentReference = selectedParentDocumentReference;
	}

	public DocumentReference getSelectedChildDocumentReference() {
		return selectedChildDocumentReference;
	}

	public void setSelectedChildDocumentReference(
			DocumentReference selectedChildDocumentReference) {
		this.selectedChildDocumentReference = selectedChildDocumentReference;
	}

	public DocumentVersion getSelectedDocumentVersion() {
		return selectedDocumentVersion;
	}

	public void setSelectedDocumentVersion(DocumentVersion selectedDocumentVersion) {
		this.selectedDocumentVersion = selectedDocumentVersion;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void onClick$toolbarbuttonDocumentSave(Event event) throws Exception {
		this.documentSave();
	}

	public void onClick$menuitemDocumentSave(Event event) throws Exception {
		this.documentSave();
	}
	
	public void onClick$menuitemDocumentVersionCreate(Event event)
			throws Exception {
		this.documentVersionCreate();
	}
	
	public void onClick$menuitemDocumentVersionEdit(Event event)
			throws Exception {
		this.documentVersionEdit();
	}
	
	public void onClick$menuitemDocumentVersionDelete(Event event)
			throws Exception {
		this.documentVersionDelete();
	}
	
	public void onClick$toolbarbuttonDocumentVersionCreate(Event event)
			throws Exception {
		this.documentVersionCreate();
	}
	
	public void onClick$toolbarbuttonDocumentVersionEdit(Event event)
			throws Exception {
		this.documentVersionEdit();
	}
	
	public void onClick$toolbarbuttonDocumentVersionDelete(Event event)
			throws Exception {
		this.documentVersionDelete();
	}

	public void onClick$menuitemParentDocumentReferenceCreate(Event event)
			throws Exception {
		this.parentDocumentReferenceCreate();
	}
	
	public void onClick$menuitemParentDocumentReferenceEdit(Event event)
			throws Exception {
		this.parentDocumentReferenceEdit();
	}
	
	public void onClick$menuitemParentDocumentReferenceDelete(Event event)
			throws Exception {
		this.parentDocumentReferenceDelete();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceCreate(Event event)
			throws Exception {
		this.parentDocumentReferenceCreate();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceEdit(Event event)
			throws Exception {
		this.parentDocumentReferenceEdit();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceDelete(Event event)
			throws Exception {
		this.parentDocumentReferenceDelete();
	}

	public void onClick$menuitemChildDocumentReferenceCreate(Event event)
			throws Exception {
		this.childDocumentReferenceCreate();
	}
	
	public void onClick$menuitemChildDocumentReferenceEdit(Event event)
			throws Exception {
		this.childDocumentReferenceEdit();
	}
	
	public void onClick$menuitemChildDocumentReferenceDelete(Event event)
			throws Exception {
		this.childDocumentReferenceDelete();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceCreate(Event event)
			throws Exception {
		this.childDocumentReferenceCreate();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceEdit(Event event)
			throws Exception {
		this.childDocumentReferenceEdit();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceDelete(Event event)
			throws Exception {
		this.childDocumentReferenceDelete();
	}

	public void onClick$menuitemDocumentTagAdd(Event event)
			throws Exception {
		this.documentTagAdd();
	}

	public void onClick$menuitemDocumentTagRemove(Event event)
			throws Exception {
		this.documentTagRemove();
	}
	
	public void onClick$toolbarbuttonDocumentTagAdd(Event event)
			throws Exception {
		this.documentTagAdd();
	}

	public void onClick$toolbarbuttonDocumentTagRemove(Event event)
			throws Exception {
		this.documentTagRemove();
	}

	public void onClick$menuitemDocumentGroupAdd(Event event)
			throws Exception {
		this.documentGroupAdd();
	}

	public void onClick$menuitemDocumentGroupRemove(Event event)
			throws Exception {
		this.documentGroupRemove();
	}
	
	public void onClick$toolbarbuttonDocumentGroupAdd(Event event)
			throws Exception {
		this.documentGroupAdd();
	}

	public void onClick$toolbarbuttonDocumentGroupRemove(Event event)
			throws Exception {
		this.documentGroupRemove();
	}

	private void documentSave() throws Exception {
		if (this.document.getTitle() != null && this.document.getDocumentCategory() != null && this.document.getDocumentType() != null) {
			this.documentService.save(this.document);
			this.sessionScope.put("CRYSTALRANGE_MESSAGE", new Message("Saved successfully!"));
			Clients.evalJavaScript("window.history.back();");
		} else {
			this.message.setText("You must enter 'Document Title', select 'Document Category' and 'Document Type'.");
            this.message.setIcon("/img/exclamation.png");
            this.binder.loadAll();
		}
	}

	private void documentVersionCreate() throws Exception {
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		User currentUser = this.userService.findByUsername(username);
		
		DocumentVersion documentVersion = new DocumentVersion();
		documentVersion.setDocument(this.document);
		documentVersion.setCreatedBy(currentUser);
		documentVersion.setCreatedDate(new Date());
		this.execution.setAttribute("documentVersion", documentVersion);
		
		Window window = (Window) this.execution.createComponents("~./zul/html/documentVersion.zul", null, null);
		window.setParent(self);
		window.doModal();
		
		if (this.execution.getAttribute("result") == "ok") {
			this.document.getDocumentVersions().add((DocumentVersion) this.execution.getAttribute("documentVersion"));
		}

		this.binder.loadAll();
	}
	
	private void documentVersionEdit() throws Exception {
		if (this.selectedDocumentVersion != null) {
			this.execution.setAttribute("documentVersion",this.selectedDocumentVersion);
	
			Window window = (Window) this.execution.createComponents("~./zul/html/documentVersion.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadAll();
		}
	}
	
	private void documentVersionDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxDocumentVersion.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentVersion selectedDocumentVersion = (DocumentVersion) selectedItem.getValue();
                    
                    Document document = selectedDocumentVersion.getDocument();
                    
                    for (int i = document.getChildDocumentReferences().size() - 1; i >= 0; i--) {
                    	DocumentReference documentReference = document.getChildDocumentReferences().get(i);
                    	if (documentReference.getParentDocumentVersion() == selectedDocumentVersion) {
                    		document.getChildDocumentReferences().remove(documentReference);
                    	}
                    	if (documentReference.getChildDocumentVersion() == selectedDocumentVersion) {
                    		document.getChildDocumentReferences().remove(documentReference);
                    	}
					}
                    
                    for (int i = document.getParentDocumentReferences().size() - 1; i >= 0; i--) {
                    	DocumentReference documentReference = document.getParentDocumentReferences().get(i);
                    	if (documentReference.getChildDocumentVersion() == selectedDocumentVersion) {
                    		document.getParentDocumentReferences().remove(documentReference);
                    	}
                    	if (documentReference.getParentDocumentVersion() == selectedDocumentVersion) {
                    		document.getParentDocumentReferences().remove(documentReference);
                    	}
					}
                    
                    for (DocumentVersion documentVersion : document.getDocumentVersions()) {
                    	for (int i = documentVersion.getChildDocumentReferences().size() - 1; i >= 0; i--) {
                        	DocumentReference documentReference = documentVersion.getChildDocumentReferences().get(i);
                        	if (documentReference.getParentDocumentVersion() == selectedDocumentVersion) {
                        		documentVersion.getChildDocumentReferences().remove(documentReference);
                        	}
                        	if (documentReference.getChildDocumentVersion() == selectedDocumentVersion) {
                        		documentVersion.getChildDocumentReferences().remove(documentReference);
                        	}
    					}
                    	for (int i = documentVersion.getParentDocumentReferences().size() - 1; i >= 0; i--) {
                        	DocumentReference documentReference = documentVersion.getParentDocumentReferences().get(i);
                        	if (documentReference.getChildDocumentVersion() == selectedDocumentVersion) {
                        		documentVersion.getParentDocumentReferences().remove(documentReference);
                        	}
                        	if (documentReference.getParentDocumentVersion() == selectedDocumentVersion) {
                        		documentVersion.getParentDocumentReferences().remove(documentReference);
                        	}
    					}
                    }
                    
                    this.document.getDocumentVersions().remove(selectedDocumentVersion);
                }
                this.selectedDocumentVersion = null;
            }
        } else {
            this.message.setText("Please select at least one item!");
            this.message.setIcon("/img/exclamation.png");
        }

        this.binder.loadAll();
	}


	private void parentDocumentReferenceCreate() throws Exception {
		DocumentReference documentReference = new DocumentReference();
		documentReference.setChildDocument(this.document);

		this.execution.setAttribute("documentReference", documentReference);
		this.execution.setAttribute("documentVersionDisabled", "childDocumentVersion");
		this.execution.setAttribute("documentDisabled", "childDocument");

		Window window = (Window) this.execution.createComponents("~./zul/html/documentReference.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			this.document.getParentDocumentReferences().add((DocumentReference) this.execution.getAttribute("documentReference"));
		}

		this.binder.loadComponent(this.listboxParentDocumentReference);

	}
	
	private void parentDocumentReferenceEdit() throws Exception {
		if (this.selectedParentDocumentReference != null) {
			this.execution.setAttribute("documentReference",this.selectedParentDocumentReference);
			this.execution.setAttribute("documentVersionDisabled", "childDocumentVersion");
			this.execution.setAttribute("documentDisabled", "childDocument");
		
			Window window = (Window) this.execution.createComponents("~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadComponent(this.listboxParentDocumentReference);
		}
	}
	
	private void parentDocumentReferenceDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxParentDocumentReference.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentReference documentReference = (DocumentReference) selectedItem.getValue();
                    this.document.getParentDocumentReferences().remove(documentReference);
                    this.document.getChildDocumentReferences().remove(documentReference);
                    
	                for (DocumentVersion documentVersion : this.document.getDocumentVersions()) {
	                	documentVersion.getParentDocumentReferences().remove(documentReference);
	                	documentVersion.getChildDocumentReferences().remove(documentReference);
	                }
	                
                }
                this.selectedParentDocumentReference = null;
            }
        } else {
            this.message.setText("Please select at least one item!");
            this.message.setIcon("/img/exclamation.png");
        }

        this.binder.loadAll();
	}

	private void childDocumentReferenceCreate() throws Exception {
		DocumentReference documentReference = new DocumentReference();
		documentReference.setParentDocument(this.document);

		this.execution.setAttribute("documentReference", documentReference);
		this.execution.setAttribute("documentVersionDisabled", "parentDocumentVersion");
		this.execution.setAttribute("documentDisabled", "parentDocument");

		Window window = (Window) this.execution.createComponents("~./zul/html/documentReference.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			this.document.getChildDocumentReferences().add((DocumentReference) this.execution.getAttribute("documentReference"));
		}

		this.binder.loadComponent(this.listboxChildDocumentReference);
	}
	
	private void childDocumentReferenceEdit() throws Exception {
		if (this.selectedChildDocumentReference != null) {
			this.execution.setAttribute("documentReference",this.selectedChildDocumentReference);
			this.execution.setAttribute("documentVersionDisabled", "parentDocumentVersion");
			this.execution.setAttribute("documentDisabled", "parentDocument");
		
			Window window = (Window) this.execution.createComponents("~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadComponent(this.listboxChildDocumentReference);
		}
	}
	
	private void childDocumentReferenceDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxChildDocumentReference.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentReference documentReference = (DocumentReference) selectedItem.getValue();
                    this.document.getParentDocumentReferences().remove(documentReference);
                    this.document.getChildDocumentReferences().remove(documentReference);
                    
	                for (DocumentVersion documentVersion : this.document.getDocumentVersions()) {
	                	documentVersion.getParentDocumentReferences().remove(documentReference);
	                	documentVersion.getChildDocumentReferences().remove(documentReference);
	                }                  
                }
                this.selectedChildDocumentReference = null;
            }
        } else {
            this.message.setText("Please select at least one item!");
            this.message.setIcon("/img/exclamation.png");
        }

        this.binder.loadAll();
	}

	@Override
	public void doAfterCompose(Component component) throws Exception {
		super.doAfterCompose(component);

		if (this.execution.getParameter("Id") != null) {
			this.document = this.documentService.find(Long.parseLong(this.execution.getParameter("Id")));
			this.labelTitle.setValue("Edit Document");
		} else {
			this.document = this.documentService.create(SecurityContextHolder.getContext().getAuthentication().getName());
			this.labelTitle.setValue("Create Document");
		}

		component.setAttribute("controller", this);
	}

	private void documentTagAdd() throws Exception {
		Window window = (Window) this.execution.createComponents("~./zul/html/documentTagSelect.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			DocumentTag selectedDocumentTag = (DocumentTag) this.execution.getAttribute("selectedDocumentTag");
			this.document.getDocumentTags().add(selectedDocumentTag);
		}

		this.binder.loadComponent(this.listboxDocumentTag);
	}

	private void documentTagRemove() throws Exception {
		Set<Listitem> selectedItems = this.listboxDocumentTag.getSelectedItems();

		for (Listitem selectedItem : selectedItems) {
			DocumentTag selectedDocumentTag = (DocumentTag) selectedItem.getValue();
			this.document.getDocumentTags().remove(selectedDocumentTag);
		}

		this.binder.loadComponent(this.listboxDocumentTag);
	}

	private void documentGroupAdd() throws Exception {
		Window window = (Window) this.execution.createComponents("~./zul/html/documentGroupSelect.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			DocumentGroup selectedDocumentGroup = (DocumentGroup) this.execution.getAttribute("selectedDocumentGroup");
			this.document.getDocumentGroups().add(selectedDocumentGroup);
		}

		this.binder.loadComponent(this.listboxDocumentGroup);
	}

	private void documentGroupRemove() throws Exception {
		Set<Listitem> selectedItems = this.listboxDocumentGroup.getSelectedItems();

		for (Listitem selectedItem : selectedItems) {
			DocumentGroup selectedDocumentGroup = (DocumentGroup) selectedItem.getValue();
			this.document.getDocumentGroups().remove(selectedDocumentGroup);
		}

		this.binder.loadComponent(this.listboxDocumentGroup);
	}

	public void onOpen$bandboxDocumentType(Event event) throws Exception {
		Window window = (Window) this.execution.createComponents("~./zul/html/documentTypeSelect.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			DocumentType selectedDocumentType = (DocumentType) this.execution.getAttribute("selectedDocumentType");
			this.document.setDocumentType(selectedDocumentType);
		}

		this.binder.loadAll();
	}

	public void onOpen$bandboxDocumentCategory(Event event) throws Exception {
		Window window = (Window) this.execution.createComponents("~./zul/html/documentCategorySelect.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			DocumentCategory selectedDocumentCategory = (DocumentCategory) this.execution.getAttribute("selectedDocumentCategory");
			this.document.setDocumentCategory(selectedDocumentCategory);
		}

		this.binder.loadAll();
	}
}
